package classfile

import "fmt"

// 文件结构（参考jvm规范）
type ClassFile struct {
	magic             uint32
	minorVersion      uint16
	majorVersion      uint16
	constantPoolCount uint16
	constantPool      ConstantPool
	accessFlags       uint16
	thisClass         uint16
	superClass        uint16
	interfacesCount   uint16
	interfaces        []uint16
	fieldsCount       uint16
	fields            []*MemberInfo
	methodsCount      uint16
	methods           []*MemberInfo
	attributesCount   uint16
	attributes        []AttributeInfo
}

func Parse(classData []byte) (cf *ClassFile, err error) {
	// 错误处理机制
	defer func() {
		if r := recover(); r != nil {
			var ok bool
			// 类型断言，将r转为error
			err, ok = r.(error)
			if !ok {
				err = fmt.Errorf("%v", r)
			}
		}
	}()
	cr := &ClassReader{classData}
	cf = &ClassFile{}
	cf.read(cr)
	return
}

// read() 方法调用其他方法来解析class文件
func (self *ClassFile) read(reader *ClassReader) {
	self.readAndCheckMagic(reader)
	self.readAndCheckVersion(reader)
	self.constantPoolCount = readConstantPoolCount(reader)
	self.constantPool = readConstantPool(reader, self.constantPoolCount)
	self.accessFlags = reader.readUint16()
	self.thisClass = reader.readUint16()
	self.superClass = reader.readUint16()
	self.interfaces = reader.readUint16s()
	self.interfacesCount = uint16(len(self.interfaces))
	self.fieldsCount = readCount(reader)
	self.fields = readMembers(reader, self.constantPool, self.fieldsCount)
	self.methodsCount = readCount(reader)
	self.methods = readMembers(reader, self.constantPool, self.methodsCount)
	self.attributesCount = readAttCount(reader)
	self.attributes = readAttributes(reader, self.constantPool, self.attributesCount)
}

// 解析魔数
func (self *ClassFile) readAndCheckMagic(reader *ClassReader) {
	self.magic = reader.readUint32()
	//fmt.Println(magic)
	if self.magic != 0xCAFEBABE {
		panic("java.lang.ClassFormatError: magic!")
	}
}

// 解析版本号
func (self *ClassFile) readAndCheckVersion(reader *ClassReader) {
	// 副版本号
	self.minorVersion = reader.readUint16()
	// 主版本号
	self.majorVersion = reader.readUint16()
	switch self.majorVersion {
	// 只有主版本号为45时，才有副版本参数
	case 45:
		return
	case 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65:
		if self.minorVersion == 0 {
			//fmt.Printf("the version is: %v.%v\n", self.majorVersion, self.minorVersion)
			return
		}
	}
	panic("java.lang.UnsupportedClassVersionError")
}

// getters
func (self *ClassFile) Magic() uint32 {
	return self.magic
}
func (self *ClassFile) MinorVersion() uint16 {
	return self.minorVersion
}
func (self *ClassFile) MajorVersion() uint16 {
	return self.majorVersion
}
func (self *ClassFile) ConstantPool() ConstantPool {
	return self.constantPool
}
func (self *ClassFile) AccessFlags() uint16 {
	return self.accessFlags
}
func (self *ClassFile) Fields() []*MemberInfo {
	return self.fields
}
func (self *ClassFile) Methods() []*MemberInfo {
	return self.methods
}
func (self *ClassFile) ConstantPoolCount() uint16 {
	return self.constantPoolCount
}
func (self *ClassFile) InterfacesCount() uint16 {
	return self.interfacesCount
}
func (self *ClassFile) FieldsCount() uint16 {
	return self.fieldsCount
}
func (self *ClassFile) MethodsCount() uint16 {
	return self.methodsCount
}
func (self *ClassFile) ClassName() string {
	return self.constantPool.getClassName(self.thisClass)
}
func (self *ClassFile) SuperClassName() string {
	if self.superClass > 0 {
		spName := self.constantPool.getClassName(self.superClass)
		//fmt.Println("when parse, the superClass name: ", spName)
		return spName
	}
	// Object
	return ""
}
func (self *ClassFile) InterfaceNames() []string {
	interfaceNames := make([]string, len(self.interfaces))
	for i, cpIndex := range self.interfaces {
		interfaceNames[i] = self.constantPool.getClassName(cpIndex)
	}
	return interfaceNames
}
